package com.csii.adhoc.JdbcTemplate;

import com.alibaba.druid.pool.DruidDataSource;
import com.csii.adhoc.exception.ParamValidityException;
import com.csii.adhoc.util.ParamCheckUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.StringUtils;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;

/**
 * @description: 操作外部连接工具类
 * @author: panChuanJiang
 * @create: 2021-01-14 14:33
 */
@Slf4j
public class JdbcTemplateFactory {
    public JdbcTemplateFactory(int cacheSize) {
        this.cacheSize = cacheSize;
    }

    private int cacheSize = 1;

    private Map<String, JdbcTemplate> cache = new LinkedHashMap<String, JdbcTemplate>(cacheSize, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, JdbcTemplate> eldest) {
            return size() > cacheSize;
        }
    };

    /**
     * 根据连接配置获取JdbcTemplate
     *
     * @param config
     * @return
     */
    public JdbcTemplate getBean(DataSourceConfig config) {
        if (StringUtils.isEmpty(config.getConnId())) {
            throw new ParamValidityException("连接信息不合法：" + config.getConnId());
        }
        if (!cache.containsKey(config.getConnId())) {
            synchronized (JdbcTemplateFactory.class) {
                if (!cache.containsKey(config.getConnId())) {
                    JdbcTemplate template = getJdbcTemplateFromConifg(config);
                    cache.put(config.getConnId(), template);
                    return template;
                }
            }
        }
        return cache.get(config.getConnId());
    }

    /**
     * 获取缓存的连接
     *
     * @param connId
     * @return
     */
    public JdbcTemplate getCacheBean(String connId) {
        if (cache.containsKey(connId)) {
            return cache.get(connId);
        }
        return null;
    }

    /**
     * 移除缓存接口
     *
     * @param connId 缓存id
     */
    public void removeJdbcTemplate(String connId) {
        if (cache.containsKey(connId)) {
            synchronized (JdbcTemplateFactory.class) {
                cache.remove(connId);
            }
        }
    }

    /**
     * 测试连接信息是否可用接口
     *
     * @param config
     * @return
     */
    public static boolean testConnConfigAvailable(DataSourceConfig config) {
        if (ParamCheckUtils.checkStringEmpty(config.getUrl(), config.getUsername(), config.getPasswd(),
                config.getDriverClass())) {
            throw new ParamValidityException("连接信息不能为空");
        }
        Connection conn = null;
        try {
            Class.forName(config.getDriverClass());
            conn = DriverManager.getConnection(config.getUrl(), config.getUsername(), config.getPasswd());
            DatabaseMetaData metaData = conn.getMetaData();
            log.info("连接的数据库为：{} - {}", metaData.getDatabaseProductName(), metaData.getDatabaseProductVersion());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    conn = null;
                }
            }

        }
    }

    private JdbcTemplate getJdbcTemplateFromConifg(DataSourceConfig config) {
        checkConfig(config);
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(config.getDriverClass());
        dataSource.setUrl(config.getUrl());
        dataSource.setUsername(config.getUsername());
        dataSource.setPassword(config.getPasswd());
        dataSource.setInitialSize(Optional.ofNullable(config.getInitialSize()).orElse(1));//初始化连接池大小
        dataSource.setMinIdle(Optional.ofNullable(config.getMinidle()).orElse(1));//连接池中保留最小连接数
        dataSource.setMaxActive(Optional.ofNullable(config.getMaxActive()).orElse(10));//连接池中保留的最大连接数
        dataSource.setMaxWait(Optional.ofNullable(config.getMaxWait()).orElse(2000));//最大等待时间(以毫秒计数)
        dataSource.setTimeBetweenEvictionRunsMillis(Optional.ofNullable(config.getTimeRunsMillis()).orElse(60000));//配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒
        dataSource.setMinEvictableIdleTimeMillis(Optional.ofNullable(config.getMinTimeMillis()).orElse(300000));
        if (!StringUtils.isEmpty(config.getValidationQuery())) {
            dataSource.setValidationQuery(config.getValidationQuery());
        }
        dataSource.setTestOnBorrow(Optional.ofNullable(config.getTestOnBorrow()).orElse(false));
        dataSource.setTestOnReturn(Optional.ofNullable(config.getTestOnReturn()).orElse(false));
        dataSource.setTestWhileIdle(Optional.ofNullable(config.getTestWhileIdle()).orElse(true));
        try {
            String filters = config.getFilters();
            if (!StringUtils.isEmpty(filters) && !config.getDriverClass().toLowerCase().contains("goldilocks")) {//goldilocks不支持设置此参数
                dataSource.setFilters(config.getFilters());
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(Optional.ofNullable(config.getMaxConnectionSize()).orElse(10));
        dataSource.setPoolPreparedStatements(Optional.ofNullable(config.getPoolPreparedStatements()).orElse(true));
        return new JdbcTemplate(dataSource);
    }

    private void checkConfig(DataSourceConfig config) {
        boolean flag = ParamCheckUtils.checkStringEmpty(config.getConnId(), config.getDriverClass(), config.getPasswd(), config.getUsername(),
                config.getUrl());
        if (flag) {
            throw new ParamValidityException("连接信息不合法：" + config);
        }
    }
}
